#pragma once
#include "config.hpp"
#include "util.hpp"
#include <pthread.h>
#include <unordered_map>
namespace cloud
{
    struct BackupInfo
    {
        bool flag_;
        size_t fsize_;
        int mtime_;
        int atime_;
        std::string real_path_;
        std::string url_;       // 下载路径
        std::string pack_path_; // 压缩文件路径(包含文件名)"./packdir/文件名.lz
        bool NewBackupInfo(const std::string &filename)//./hello.txt
        {
            flag_ = false;
            Fileutil fu(filename);
            fsize_ = fu.fileSize();
            mtime_ = fu.fileModtime();
            atime_ = fu.fileAcctime();
            Config *cfg = Config::GetInstance();
            std::string name = fu.Filename();
            url_ = cfg->GetDprefix() + name;// /download/hello.txt
            real_path_ = filename;
            pack_path_ = cfg->GetPackfile() + name + cfg->GetPacksuffix();
        }
    };
    class DataManager
    {
    private:
        pthread_rwlock_t lock_;
        std::unordered_map<std::string, BackupInfo> um;
        std::string backupfile_; // 备份文件路径"./cloud.dat"
        DataManager()
        {
            Config* cfg = Config::GetInstance();
            backupfile_ = cfg->GetBackUpfile();
            pthread_rwlock_init(&lock_, nullptr);
            InitLoad();
        }
    public:
       
        static DataManager* GetInstance()
        {
            static DataManager data;
            return &data;
        }
        ~DataManager()
        {
            pthread_rwlock_destroy(&lock_);
        }
        bool Insert(const BackupInfo &info)
        {
            pthread_rwlock_wrlock(&lock_);
            um[info.url_] = info;
            pthread_rwlock_unlock(&lock_);
            Storage();
            return true;
        }
        bool Update(const BackupInfo &info)
        {
            pthread_rwlock_wrlock(&lock_);
            um[info.url_] = info;
            pthread_rwlock_unlock(&lock_);
            Storage();
            return true;
        }
        bool GetOnebyurl(const std::string &url, BackupInfo *info)
        {
            // /download/
            pthread_rwlock_rdlock(&lock_);
            if (um.find(url) == um.end())
            {
                pthread_rwlock_unlock(&lock_);
                return false;
            }
            *info = um[url];
            pthread_rwlock_unlock(&lock_);
            return true;
        }
        bool GetOnebyrealpath(const std::string &real_path, BackupInfo *info)
        {
            //./hello.txt
            pthread_rwlock_rdlock(&lock_);
            for (auto &e : um)
            {
                if (e.second.real_path_ == real_path)
                {
                    *info = e.second;
                    pthread_rwlock_unlock(&lock_);
                    return true;
                }
            }
            pthread_rwlock_unlock(&lock_);
            return false;
        }
        bool GetAll(std::vector<BackupInfo> *info)
        {
            pthread_rwlock_rdlock(&lock_);
            for (auto &e : um)
            {
                info->push_back(e.second);
            }
            pthread_rwlock_unlock(&lock_);
            return true;
        }
        bool InitLoad()
        {
            Fileutil fu(backupfile_);
            std::string body;
            fu.GetContent(&body);
            Json::Value root;
            Jsonutil::Unserialize(body,&root);
            for (int i = 0; i < root.size();i++)
            {
                BackupInfo info;
                info.flag_ = root[i]["flag"].asBool();
                info.atime_ = root[i]["atime"].asInt();
                info.mtime_ = root[i]["mtime"].asInt();
                info.fsize_ = root[i]["fsize"].asInt();
                info.pack_path_ = root[i]["pack_path"].asString();
                info.real_path_ = root[i]["real_path"].asString();
                info.url_ = root[i]["url"].asString();
                um[info.url_] = info;
            }
        }
        bool Storage()
        {
            std::vector<BackupInfo> vb;
            if (GetAll(&vb) == false)
            {
                return false;
            }

            Json::Value root;
            for (auto &e : vb)
            {
                Json::Value item;
                item["flag"] = e.flag_;
                item["atime"] = e.atime_;
                item["mtime"] = e.mtime_;
                item["fsize"] = (Json::Int)(e.fsize_); // 要类型强转
                item["pack_path"] = e.pack_path_;
                item["real_path"] = e.real_path_;
                item["url"] = e.url_;
                root.append(item);
            }
            // 反序列化
            std::string body;
            Jsonutil::serialize(&body, root);
            // 写入文件
            Fileutil fu(backupfile_);//./cloud.dat"
            fu.SetContent(body);
            return true;
        }
    };
}
